' binplugin.bmx

Strict

Import BRL.Basic

Import "../maxtk/maxtk.bmx"

Type TBinOptions Extends TOptionsPage
	Field	owner:TBinPlugin

	Field	editcolor:TColorButton
	Field	editfont:TFontButton
	Field	editstyle:TTextStyle

	Method CreateBinOptions:TBinOptions(plugin:TBinPlugin)
		SetName "Bin Options"
		owner=plugin
		plugin.editor.hostoptions.AddPage Self
		editcolor=AddColorButton("Binary Color",-1)		
		editfont=AddFontButton("Binary Font","Courier",12,0)
		editstyle=AddTextStyle(Self,"Style")		
		layout
		Return Self
	End Method
End Type

Type TBinPlugin Extends TPlugin

	Field	editor:TEditor
	Field	options:TBinOptions
	Field	editmenu:TGadget

	Method Open:Object(path$)
		Return TBinCode.Open(Self,path)
	End Method
	
	Method Initialize(owner:THost)
		host=owner
		SetName("Bin",["bin","exe","dll"])
		editor=TEditor(host)
		If Not editor RuntimeError "BinPlugin requires TEditor Host"
		options=New TBinOptions.CreateBinOptions(Self)
		editmenu=CreateEditMenu()
	End Method

	Function CreateEditMenu:TGadget()
		Local	edit:TGadget
		Const MKEY$=Chr(8)
		edit=CreateMenu("&Edit",0,Null)
		CreateMenu "&Quick Help"+MKEY+"F1",MENUQUICKHELP,edit
		Return edit
	End Function

End Type

Type TBinCode Extends TOpenFile
	Field	plugin:TBinPlugin
	Field	host:THost
	Field	textarea:TGadget
	Field	sizecombo:TGadget
	Field	dirty=True	
	Field	bank:TBank
	Field	bytes
	Field	undolist:TList=New TList
	Field	wordsize=1
	Field	wordcount=16

	Function Open:TBinCode(plugin:TBinPlugin,path$)
		Local	code:TBinCode
		code=New TBinCode
		code.plugin=plugin
		code.host=plugin.host
'		code.options=plugin.options		
		code.active=True
		code.path=path
		code.host.addpanel(code)	
'		code.textarea=CreateTextArea(0,0,ClientWidth(code.panel),ClientHeight(code.panel),code.panel,0)
		code.textarea=CreateTextArea(0,24,ClientWidth(code.panel),ClientHeight(code.panel),code.panel,0)
		
		code.sizecombo=CreateComboBox(4,2,128,22,code.panel)
		AddGadgetItem code.sizecombo,"Bytes",GADGETITEM_DEFAULT
		AddGadgetItem code.sizecombo,"Shorts"
		AddGadgetItem code.sizecombo,"Ints"
		AddGadgetItem code.sizecombo,"Longs"
		
		SetGadgetLayout code.textarea,1,1,1,1
		code.Refresh
		code.SetDirty False
		plugin.host.UpdateProgress "Reading Stream"
		code.ReadSource(path)
		code.BinFile
		Return code
	End Function

	Method ReadSource(path$)
		bank=LoadBank(path)
		bytes=BankSize(bank)
		Local blen=(bytes+7)&-8
		If blen>bytes ResizeBank(bank,blen)			
	End Method

	Method SetDirty( bool )
		If dirty=bool Return
		dirty=bool
		name=StripDir(path)
		If (dirty) name:+"*"
'		If (host.lockedpanel=Self) name="build:"+name
		host.RefreshPanel Self
	End Method
	
	Method SetWordSize(w)
		If w=wordsize Return
		wordsize=w
		wordcount=24 / w
		BinFile
	End Method

	Method OnEvent()
		Local w
 		Select EventSource()
			Case sizecombo
				w=1 Shl EventData()
				SetWordSize(w)
		End Select
	End Method
	
	Method Invoke(command$,argument:Object=Null)
		Local	file$,ex$
		Local	p,res
		Select command
			Case "SHOW"
				host.SetTitle path				
				If textarea ActivateGadget textarea
			Case "CLOSE"
				host.RemovePanel Self
			Case "ACTIVATE"
				If textarea ActivateGadget textarea
			Case "REFRESH"
				Refresh
		End Select
	End Method
		
	Method Refresh()
		Local	options:TBinOptions
		Local	rgb:TColorButton		
		options=plugin.options
		SetTextAreaFont textarea,options.editfont.font
		rgb=options.editcolor
		SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,True
		rgb=options.editstyle.color
		SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,False
	End Method

	Function WriteHex(value,p:Byte Ptr,bytes)
		Global HexDigits[]=[48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70]	
		Local i,nibbles
		nibbles=bytes*2-1
		For i=0 To nibbles
			p[nibbles-i]=HexDigits[value&15]
			value=value Shr 4
		Next
	End Function
	
	Method BinFile()
		Local buffer:Byte[]
		Local size		
		Local lines,count,l
		Local dest:Byte Ptr
		Local s$,n		
		count=wordcount*wordsize	
		lines=(bytes+count-1)/count
		size=lines*(count*3+wordcount+16)
		buffer=New Byte[size]
		dest=buffer
		For l=0 Until lines
			dest=BinLine(l,dest)	
		Next
		n=Int(dest)-Int(Byte Ptr buffer)
		s=String.FromBytes(buffer,n)
		SetTextAreaText textarea,s
	End Method

	Method BinLine:Byte Ptr(line,dest:Byte Ptr)		
		Local src,stop
		Local t
		src=line*wordcount*wordsize
		If src>=bytes Return
		stop=Min(src+wordcount*wordsize,bytes)
		WriteHex(src,dest,3)
		dest[6]=32
		dest:+7
'hex column
		While src<stop		
			Select wordsize
				Case 1
					t=PeekByte(bank,src)
					src:+1
					WriteHex t,dest,1
					dest[2]=32
					dest:+3
				Case 2
					t=PeekShort(bank,src)
					src:+2
					WriteHex t,dest,2
					dest[4]=32
					dest:+5
				Case 4
					t=PeekInt(bank,src)
					src:+4
					WriteHex t,dest,4
					dest[8]=32
					dest:+9
				Case 8
					t=PeekLong(bank,src)
					src:+8
					WriteHex t,dest,8
					dest[16]=32
					dest:+17
				Default
					RuntimeError "illegal wordsize"
			End Select
		Wend
'ascii column
		src=line*wordcount*wordsize
		While src<stop
			t=PeekByte(bank,src)
			If t<32 t=46
			dest[0]=t
			src:+1
			dest:+1
		Wend
					
		dest[0]=13
		Return dest+1
	End Method
	
End Type

